package zhongbo.java.air.monitor.task;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import zhongbo.java.air.dictionary.model.AirPort;
import zhongbo.java.air.dictionary.model.AlertZone;
import zhongbo.java.air.monitor.config.RedisListenerConfig;
import zhongbo.java.air.monitor.dto.PointDto;
import zhongbo.java.air.monitor.listener.RedisLogChanelPublisher;
import zhongbo.java.air.monitor.mapper.AirAlertLogMapper;
import zhongbo.java.air.monitor.mapper.FlightActivityDailyMapper;
import zhongbo.java.air.monitor.model.AirAlertLog;
import zhongbo.java.air.monitor.model.FlightActivityDaily;
import zhongbo.java.air.monitor.service.impl.FlightActivityDailyServiceImpl;
import zhongbo.java.air.monitor.service.impl.JtsServiceImpl;
import zhongbo.java.air.monitor.util.JtsUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 说明：
 *
 * @author 钟波dellNotebook
 * @since 2025年04月08日 星期二 04:12:59
 */
@Component
@Slf4j
public class AircraftActivityTask {

    List<FlightActivityDaily> updatedActivities = new ArrayList<>();// 收集需要推送的消息的列表

    @Autowired
    private FlightActivityDailyMapper flightActivityDailyMapper;

    @Autowired
    private JtsServiceImpl jtsService;

    @Autowired
    private AirAlertLogMapper airAlertLogMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    // 每10分钟执行（注意配置时区）
    @Scheduled(
            // 开发中可设置短一点, 这里设置5分钟
            fixedDelay = 5 * 60 * 1000
            // 启动后等多少毫秒, 执行第一次定时任务, 这里设置5秒
            , initialDelay = 5000
            , zone = "Asia/Shanghai"
    )
    public void updateDailyActivity() {
        log.info("---- 执行定时任务 -----");
        doJob(); // 更新/新增 并 推送至 alert_zone_channel 频道
        checkAlertZones();
        log.info("---- 定时任务已结束 ------");
    }

    private void doJob() {
        String today = DateUtil.formatDate(new Date());
        // 1. 从轨迹表查询当天出现过的ICAO码（需实现轨迹表查询逻辑）
        List<FlightActivityDaily> activeICaos = flightActivityDailyMapper.selectDailyStats(today);
        log.info("查询结果: {}条", activeICaos.size());
        // 2. 批量插入或更新
        // todo 周二任务: 存入数据库. 存入之前先icao+date两个字段, 判断数据库是否已有数据, 有的话则是更新
        if (activeICaos.isEmpty()) { // activeICaos为空
            log.error("air_flight_path表什么也没有找到");
            return;
        }
        // 增强for处理所有查询结果
        for (FlightActivityDaily activityDaily :activeICaos) {
            // 先判断此次是更新还是新增:(判断icao是不是重复的)
            Boolean addorupdate = flightActivityDailyMapper.isUpOrAdd(activityDaily.getIcaoCode(), today);
            if (Boolean.TRUE.equals(addorupdate)) {
                // 提取 ID 用于更新
                activityDaily.setId(flightActivityDailyMapper.queryActivityDailyId(activityDaily.getIcaoCode()));
                // 执行更新
                int update = flightActivityDailyMapper.updateById(activityDaily);
                // 日志不好分辨，于是找ai跑了ANSI颜色代码
                log.info("\u001B[34m[UPDATE]\u001B[0m 航迹追踪 | ICAO: \u001B[36m{}\u001B[0m | 结果: {}", activityDaily.getIcaoCode(), update > 0 ? "\u001B[32m✔ 成功\u001B[0m" : "\u001B[33m⚠ 无变化\u001B[0m");
            } else {
                // 设置日期并执行新增
                activityDaily.setDate(new Date());
                int insert = flightActivityDailyMapper.insert(activityDaily);
                log.info("\u001B[33m[INSERT]\u001B[0m 航迹追踪 | ICAO: \u001B[36m{}\u001B[0m | 结果: {}", activityDaily.getIcaoCode(), insert > 0 ? "\u001B[32m✔ 成功\u001B[0m" : "\u001B[31m✘ 失败\u001B[0m");
            }

            updatedActivities.add(activityDaily);
        }

        // 批量推送更新后的数据
        if (!updatedActivities.isEmpty()) {
            try {
                redisTemplate.convertAndSend(RedisListenerConfig.ALERT_ZONE_CHANNEL, updatedActivities); // 推送给redis订阅频道
                log.info("\u001B[32m[REDIS]\u001B[0m 成功推送所有条航迹更新数据");
            } catch (Exception e) {
                log.error("\u001B[31m[REDIS-ERROR]\u001B[0m 推送航迹数据失败: {}", e.getMessage());
            }
        }

        List<AlertZone> alertZoneList = flightActivityDailyMapper.alertZoneList();
        if (alertZoneList.isEmpty()) {
            log.error("\u001B[31m✘ 警戒区数据为空\u001B[0m | 当前未设立任何警戒区");
        } else {
            redisTemplate.convertAndSend(RedisListenerConfig.ALERT_ZONE_CHANNEL, alertZoneList);

            log.info("\u001B[32m✔ 警戒区推送成功\u001B[0m | 数量: \u001B[36m{}\u001B[0m | 通道: \u001B[33m{}\u001B[0m", alertZoneList.size(), RedisListenerConfig.ALERT_ZONE_CHANNEL);

        }

    }

//    public void checkAlertZones() {
//        String today = DateUtil.formatDate(new Date());
//        // 取所有今日活跃航班记录
//        List<FlightActivityDaily> flightActivityDailies = flightActivityDailyMapper.flightActivityDailyList();
//        // 取所有警戒地区
//        List<AlertZone> alertZoneList = flightActivityDailyMapper.alertZoneList();
//        if (alertZoneList.isEmpty()) {
//            log.error("\u001B[33m⚠ 未配置任何警戒区，无法检查\u001B[0m");
//            return;
//        }
//        for (FlightActivityDaily flightActivityDaily : flightActivityDailies) {
//
//            String redisKey = "alert:history:" + flightActivityDaily.getIcaoCode();
//
//            if (redisTemplate.hasKey(redisKey)) {
//                log.debug("这个航班:{}已警告过一次了！",flightActivityDaily.getIcaoCode());
//            }
//
//            for (AlertZone alertZone : alertZoneList) {
//                List<PointDto> pointDtoList = jtsService.parseAlertZoneVertices(alertZone.getVertices()); // 解析多面性顶点
//                if (pointDtoList.isEmpty()) {
//                    log.error("警戒区 {} 数据没有东西", alertZone.getId());
//                    return;
//                }
//                if (jtsService.isInAlertZone(pointDtoList, flightActivityDaily.getLastLongitude(), flightActivityDaily.getLastLatitude())) {
//                    AirAlertLog airAlertLog = new AirAlertLog();
//
//                    airAlertLog.setAlertZoneId(alertZone.getId());
//                    airAlertLog.setIcaoCode(flightActivityDaily.getIcaoCode());
//                    airAlertLog.setAlertZoneCode(alertZone.getZoneType());
//
//
//
//                    airAlertLogMapper.insert(airAlertLog);
//                }
//            }
//        }
public void checkAlertZones() {
//    String today = DateUtil.formatDate(new Date());
    List<FlightActivityDaily> flights = flightActivityDailyMapper.flightActivityDailyList();
    List<AlertZone> alertZones = flightActivityDailyMapper.alertZoneList();

    if (alertZones.isEmpty()) {
        log.error("\u001B[33m⚠ 未配置警戒区\u001B[0m");
        return;
    }

    int alertCount = 0;
    for (FlightActivityDaily flight : flights) {
        String icao = flight.getIcaoCode();
        String redisKey = "alert:history:tjp:" + icao;

        // 防重复检查
        if (redisTemplate.hasKey(redisKey)) {
            log.debug("航班 {} 5分钟内已有告警", icao);
            continue;
        }

        // 2.2 警戒区检查
        for (AlertZone zone : alertZones) {
            try {
                // jts工具类处理坐标
                List<PointDto> vertices = jtsService.parseAlertZoneVertices(zone.getVertices());
                if (vertices == null) {
                    log.error("警戒区 {} 顶点数据无效", zone.getId());
                    continue;
                }

                // 转换为jts多边形
                Coordinate[] coordinates = vertices.stream()
                        .map(v -> JtsUtil.createCoordinate(v.getLongitude(), v.getLatitude()))
                        .toArray(Coordinate[]::new);
                Polygon polygon = JtsUtil.createPolygon(coordinates);

                // 创建航班坐标点
                Point point = JtsUtil.createPoint(flight.getLastLongitude(), flight.getLastLatitude());

                // 判断标点在不在警告区域内
                if (JtsUtil.isPointInPolygon(point, polygon)) {
                    // 3. 告警处理（保持原有结构）
                    AirAlertLog alertLog = buildAlertLog(flight, zone);
                    airAlertLogMapper.insert(alertLog);

                    redisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(alertLog), 5, TimeUnit.MINUTES);

                    redisTemplate.convertAndSend(RedisListenerConfig.ALERT_ZONE_CHANNEL, alertLog);

                    log.warn("\u001B[31m🚨 警告\u001B[0m 航班:{} 区域:{}", icao, zone.getZoneCode());
                    alertCount++;
                    break; // 命中一个区域即停止
                }
            } catch (Exception e) {
                log.error("检查失败 [航班:{} 区域:{}] {}", icao, zone.getId(), e.getMessage());
            }
        }
    }
    log.info("\u001B[36m✔ 完成检查\u001B[0m 航班:{} 告警:{}", flights.size(), alertCount);
}

    // 保持你原有的实体类结构
    private AirAlertLog buildAlertLog(FlightActivityDaily flight, AlertZone zone) {
        AirAlertLog log = new AirAlertLog();
        log.setId(IdUtil.fastUUID());
        log.setAlertZoneId(zone.getId());
        log.setIcaoCode(flight.getIcaoCode());
        log.setAlertType(zone.getZoneType());

        JSONObject coord = new JSONObject()
                .put("lng", flight.getLastLongitude())
                .put("lat", flight.getLastLatitude());
        log.setTriggerCoordinates(coord.toString());

        Date now = new Date();
        log.setTriggerTime(now);
        log.setCreateTime(now);
        log.setUpdateTime(now);
        log.setStatus("0");
        return log;
    }

}
